/*
* Copyright (C) 2020 ~ 2024 chaigec All Rights Reserved.
*
* Author:     chaigec <chaigec@163.com>
* Maintainer: chaigec <chaigec@163.com>

 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
*/

#include "MkRtpUdpServer.h"
#include "MkUtil/MkLog.h"

CMkRtpUdpSocket::CMkRtpUdpSocket(CMkEvent* pEvent, CMkTimer* pTimer, const MkRtpPacketCallback RtpCb)
    : CMkSocket(UdpSession, pEvent, pTimer)
    , m_RtpCb(RtpCb)
    , m_nMaxLen(Len2K)
{
    m_pRtpBuffer = (Uint8*)malloc(m_nMaxLen);
}


Uint32 CMkRtpUdpSocket::OnRecvFrom()
{
    MkString Host;
    Uint16 Port;
    Uint32 nLen = m_nMaxLen;
    Uint32 ErrorCode = RecvFrom(m_pRtpBuffer, nLen, Host, Port);
    MkCheckErrorLog(ErrorCode, "recv rtcp failed\n");

    CMkRtpPacket RtpPacket;
    if (m_RtpCb && NoneError == RtpPacket.Parse(m_pRtpBuffer, nLen)) {
        m_RtpCb(RtpPacket, Host, Port);
    }
    return NoneError;
}

CMkRtcpUdpSocket::CMkRtcpUdpSocket(CMkEvent* pEvent, CMkTimer* pTimer, const MkRtcpPacketCallback Cb)
    : CMkSocket(UdpSession, pEvent, pTimer)
    , m_nMaxLen(Len1K)
    , m_RtcpCb(Cb)
{
    m_pRtcpBuffer = (Uint8*)malloc(m_nMaxLen);
}

Uint32 CMkRtcpUdpSocket::OnRecvFrom()
{
    MkString Host;
    Uint16 Port;
    Uint32 nLen = m_nMaxLen;
    Uint32 ErrorCode = RecvFrom(m_pRtcpBuffer, nLen, Host, Port);
    MkCheckErrorLog(ErrorCode, "recv rtcp failed\n");
    Uint32 Offset = 0;
    Uint32 nUseLen = 0;
    CMkRtcpPacket RtcpPacket;
    while (m_RtcpCb && Offset < nLen) {
        ErrorCode = RtcpPacket.Parse(m_pRtcpBuffer + Offset, nLen - Offset, nUseLen);
        if (NoneError != ErrorCode) {
            break;
        }

        m_RtcpCb(RtcpPacket, Host, Port);
        Offset += nUseLen;
    }
    return NoneError;
}

BOOL CMkRtpUdpServer::m_CheckRtcpFlag = FALSE;
Uint32 CMkRtpUdpServer::m_RtcpTimeSec = 10;
CMkRtpUdpServer::CMkRtpUdpServer(CMkEvent* pEvent, CMkTimer* pTimer)
    : CMkRtp(pTimer, m_CheckRtcpFlag, m_RtcpTimeSec)
    , m_pRtpSocket(nullptr)
    , m_pRtcpSocket(nullptr)
    , m_pEvent(pEvent)
{

}

Uint32 CMkRtpUdpServer::Start(const Uint16& RtpPort)
{
    Uint16 RtcpPort = RtpPort + 1;
    m_pRtpSocket = new CMkRtpUdpSocket(m_pEvent, GetTimer(), [this](const CMkRtpPacket& RtpPacket, const MkString& SenderHost, const Uint16& SenderPort) {
        return ParseRtpPacket(RtpPacket, SenderHost, SenderPort);
    });

    Uint32 ErrorCode = m_pRtpSocket->Create();
    if (NoneError != ErrorCode) {
        MkErrorLog("rtp socket create failed\n");
        MkDelete(m_pRtpSocket);
        return ErrorCode;
    }
    ErrorCode = m_pRtpSocket->Bind(RtpPort);
    if (NoneError != ErrorCode) {
        MkErrorLog("rtp socket bind failed\n");
        MkDelete(m_pRtpSocket);
        return ErrorCode;
    }

    m_pRtcpSocket = new CMkRtcpUdpSocket(m_pEvent, GetTimer(), [this](const CMkRtcpPacket& RtcpPacket, const MkString& Host, Uint16 Port) {
        return ParseRtcpPacket(RtcpPacket, Host, Port);
    });

    ErrorCode = m_pRtcpSocket->Create();
    if (NoneError != ErrorCode) {
        MkErrorLog("rtcp socket create failed\n");
        MkDelete(m_pRtpSocket);
        MkDelete(m_pRtcpSocket);
        return ErrorCode;
    }
    ErrorCode = m_pRtcpSocket->Bind(RtpPort + 1);
    if (NoneError != ErrorCode) {
        MkErrorLog("rtcp socket bind failed\n");
        MkDelete(m_pRtpSocket);
        MkDelete(m_pRtcpSocket);
        return ErrorCode;
    }

    return NoneError;
}

Uint16 CMkRtpUdpServer::GetRtpPort() const
{
    if (m_pRtpSocket) {
        return m_pRtpSocket->GetLocalPort();
    }
    return 0;
}

Uint16 CMkRtpUdpServer::GetRtcpPort() const
{
    if (m_pRtcpSocket) {
        return m_pRtcpSocket->GetLocalPort();
    }
    return 0;
}

Uint32 CMkRtpUdpServer::SendRtpPacket(const CMkRtpPacket& RtpPacket, const MkString& RemoteIp, Uint16 RemotePort)
{
    if (m_pRtpSocket) {
        CMkBufferList BufferList;
        BufferList.Append(RtpPacket.GetHeaderData(), RtpPacket.GetHeaderLen());
        if (!RtpPacket.GetPayloadData()) {
            BufferList.Append(RtpPacket.GetPayloadBufferList());
        } else {
            BufferList.Append(RtpPacket.GetPayloadData(), RtpPacket.GetPayloadLength());
        }
        return m_pRtpSocket->SendTo(RemoteIp, RemotePort, BufferList);
    }
    return NoneError;
}

Uint32 CMkRtpUdpServer::SendRtcpPacket(const CMkRtcpPacket& RtcpPacket, const MkString& RemoteIp, Uint16 RemotePort)
{
    Uint8 pBuf[Len1K] = { 0 };
    Uint32 nUsed = 0;
    RtcpPacket.Packet(pBuf, Len1K, nUsed);
    return m_pRtcpSocket->SendTo(RemoteIp, RemotePort, pBuf, nUsed);
}

Uint32 CMkRtpUdpServer::Release()
{
    return NoneError; //do nothind
}

CMkRtpUdpServer::~CMkRtpUdpServer()
{
    MkDelete(m_pRtcpSocket);
    MkDelete(m_pRtpSocket);
}

CMkRtcpUdpSocket::~CMkRtcpUdpSocket()
{
    MkFree(m_pRtcpBuffer);
}

CMkRtpUdpSocket::~CMkRtpUdpSocket()
{
    MkFree(m_pRtpBuffer);
}